package com.goodwill.androidtest.timeline;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

import com.goodwill.androidtest.R;

public class TimelineLayout extends LinearLayout {

    private int mLineMarginLeft;
    private int mLineMarginTop;
    private int mLineMode;
    private int mLineStrokeWidth;
    private int mLineDashLength;
    private int mLineDashGap;
    private int mLineColor;

    private int mPointSize;
    private int mPointColor;
    private boolean mIsCircleRing;
    private int mCircleRingWidth;
    private int mCircleRingColor;

    private Paint mLinePaint;  //线的画笔
    private Paint mCirclePaint;  //圆的画笔
    private Paint mRingPaint;  //圆环的画笔

    public TimelineLayout(Context context) {
        this(context, null);
    }

    public TimelineLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimelineLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TimeLineLayout);
        mLineMarginLeft = ta.getDimensionPixelOffset(R.styleable.TimeLineLayout_line_margin_left, dip2px(20));
        mLineMarginTop = ta.getDimensionPixelOffset(R.styleable.TimeLineLayout_line_margin_top, 0);
        mLineMode = ta.getInt(R.styleable.TimeLineLayout_line_mode, 1);
        mIsCircleRing = ta.getBoolean(R.styleable.TimeLineLayout_isCircleRing, true);
        mCircleRingWidth = ta.getDimensionPixelSize(R.styleable.TimeLineLayout_circle_ring_width, dip2px(2));
        mCircleRingColor = ta.getColor(R.styleable.TimeLineLayout_circle_ring_color, getResources().getColor(R.color.color_3CA0FF));
        mLineDashLength = ta.getInt(R.styleable.TimeLineLayout_dashLength, 4);
        mLineDashGap = ta.getInt(R.styleable.TimeLineLayout_dashGap, 4);
        mLineStrokeWidth = ta.getDimensionPixelSize(R.styleable.TimeLineLayout_line_stroke_width, dip2px(2));
        mLineColor = ta.getColor(R.styleable.TimeLineLayout_line_color, getResources().getColor(R.color.color_3CA0FF));
        mPointSize = ta.getDimensionPixelSize(R.styleable.TimeLineLayout_point_size, dip2px(5));
        mPointColor = ta.getColor(R.styleable.TimeLineLayout_point_color, getResources().getColor(R.color.color_FFFFFF));
        setWillNotDraw(false);
        initView(context);
    }

    private void initView(Context context) {

        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setDither(true);
        mLinePaint.setColor(mLineColor);
        mLinePaint.setStrokeWidth(mLineStrokeWidth);
        if (mLineMode == 0) {
            mLinePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        } else {
            mLinePaint.setStyle(Paint.Style.STROKE);
            mLinePaint.setPathEffect(new DashPathEffect(new float[]{mLineDashLength, mLineDashGap}, 0));
        }

        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setDither(true);
        mCirclePaint.setColor(mPointColor);
        mCirclePaint.setStyle(Paint.Style.FILL);

        mRingPaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setDither(true);
        mRingPaint.setColor(mCircleRingColor);
        mRingPaint.setStrokeWidth(mCircleRingWidth);
        mRingPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int orientation = getOrientation();
        if (orientation == LinearLayout.HORIZONTAL) {
            drawHorizontalTimeLine(canvas);
        } else {
            drawVerticalTimeLine(canvas);
        }
    }

    private void drawHorizontalTimeLine(Canvas canvas) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            drawHorizontalTimeline(canvas, index);
            drawHorizontalPoint(canvas, index);
            setChildMarginTop(index);
        }
    }

    private void drawHorizontalTimeline(Canvas canvas, int index) {
        View child = getChildAt(index);
        if (child != null) {
            if (index == 0) {
                drawRightPartLine(canvas, child);
            } else if (index == getChildCount() - 1) {
                drawLeftPartLine(canvas, child);
            } else {
                drawLeftPartLine(canvas, child);
                drawRightPartLine(canvas, child);
            }
        }
    }

    private void drawVerticalTimeLine(Canvas canvas) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            drawVerticalTimeline(canvas, index);
            drawVerticalPoint(canvas, index);
            setChildMarginLeft(index);
        }
    }

    private void setChildMarginTop(int index) {
        View child = getChildAt(index);
        if (child != null) {
            LinearLayout.LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            layoutParams.topMargin = getLineMarginTop();
            child.setLayoutParams(layoutParams);
        }
    }

    private void setChildMarginLeft(int index) {
        View child = getChildAt(index);
        if (child != null) {
            LinearLayout.LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            layoutParams.leftMargin = getLineMarginLeft();
            child.setLayoutParams(layoutParams);
        }
    }

    private void drawVerticalTimeline(Canvas canvas, int index) {
        View child = getChildAt(index);
        if (child != null) {
            if (index == 0) {
                drawBottomPartLine(canvas, child);
            } else if (index == getChildCount() - 1) {
                drawTopPartLine(canvas, child);
            } else {
                drawTopPartLine(canvas, child);
                drawBottomPartLine(canvas, child);
            }
        }
    }

    private void drawLeftPartLine(Canvas canvas, View child) {
        int childLeft = child.getLeft();
        int childPaddingLeft = child.getPaddingLeft();
        int childWidth = child.getWidth();
        int startX = childLeft;
        int startY = getLineMarginTop() / 2;
        int stopX = childLeft + childPaddingLeft + childWidth / 2;
        int stopY = getLineMarginTop() / 2;
        canvas.drawLine(startX, startY, stopX, stopY, mLinePaint);
    }

    private void drawRightPartLine(Canvas canvas, View child) {
        int childLeft = child.getLeft();
        int childRight = child.getRight();
        int childPaddingLeft = child.getPaddingLeft();
        int childPaddingRight = child.getPaddingRight();
        int childWidth = child.getWidth();
        int startX = childLeft + childPaddingLeft + childWidth / 2;
        int startY = getLineMarginTop() / 2;
        int stopX = childRight - childPaddingRight;
        int stopY = getLineMarginTop() / 2;
        canvas.drawLine(startX, startY, stopX, stopY, mLinePaint);
    }

    private void drawTopPartLine(Canvas canvas, View child) {
        int childTop = child.getTop();
        int childPaddingTop = child.getPaddingTop();
        int childHeight = child.getHeight();
        int startX = getLineMarginLeft() / 2;
        int stopX = getLineMarginLeft() / 2;
        int startY = childTop;
        int stopY = childTop + childPaddingTop + childHeight / 2;
        canvas.drawLine(startX, startY, stopX, stopY, mLinePaint);
    }

    private void drawBottomPartLine(Canvas canvas, View child) {
        int childTop = child.getTop();
        int childBottom = child.getBottom();
        int childPaddingBottom = child.getPaddingBottom();
        int childPaddingTop = child.getPaddingTop();
        int childHeight = child.getHeight();
        int startX = getLineMarginLeft() / 2;
        int stopX = getLineMarginLeft() / 2;
        int startY = childTop + childPaddingTop + childHeight / 2;
        int stopY = childBottom - childPaddingBottom;
        canvas.drawLine(startX, startY, stopX, stopY, mLinePaint);
    }

    private void drawVerticalPoint(Canvas canvas, int index) {
        View child = getChildAt(index);
        if (child != null) {
            int childTop = child.getTop();
            int childPaddingTop = child.getPaddingTop();
            int childPaddingBottom = child.getPaddingBottom();
            int childHeight = child.getHeight() / 2;
            int circleX = getLineMarginLeft() / 2;
            int circleY = childTop + childPaddingTop + childHeight - childPaddingBottom;
            if (mIsCircleRing) {
                canvas.drawCircle(circleX, circleY, mPointSize + mCircleRingWidth, mRingPaint);
            }
            //画内部圆
            canvas.drawCircle(circleX, circleY, mPointSize, mCirclePaint);
        }
    }

    private void drawHorizontalPoint(Canvas canvas, int index) {
        View child = getChildAt(index);
        if (child != null) {
            int childLeft = child.getLeft();
            int childPaddingLeft = child.getPaddingLeft();
            int childPaddingRight = child.getPaddingRight();
            int childWidth = child.getWidth() / 2;
            int circleX = childLeft + childPaddingLeft + childWidth - childPaddingRight;
            int circleY = getLineMarginTop() / 2;
            if (mIsCircleRing) {
                canvas.drawCircle(circleX, circleY, mPointSize + mCircleRingWidth, mRingPaint);
            }
            //画内部圆
            canvas.drawCircle(circleX, circleY, mPointSize, mCirclePaint);
        }
    }

    public int getLineMarginLeft() {
        return mLineMarginLeft;
    }

    public void setLineMarginLeft(int lineMarginLeft) {
        this.mLineMarginLeft = lineMarginLeft;
        invalidate();
    }

    public int getLineMarginTop() {
        return mLineMarginTop;
    }

    public void setLineMarginTop(int lineMarginTop) {
        this.mLineMarginTop = lineMarginTop;
        invalidate();
    }

    public int dip2px(float dipValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    public int px2dip(float pxValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
}
